package com.example.demo.util;

import sun.misc.Unsafe;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

public class DateUtil {
    /**
     * 默认的时间格式
     */
    public static final String DEFAULT_DATE_TIME = "yyyy-MM-dd HH:mm:ss";

    private static Map<String, DateTimeFormatter> dtfMap = new WeakHashMap<>();

    private static Map<String, SimpleDateFormat> sdfMap = new WeakHashMap<>();

    public static final SimpleDateFormat DEFAULT_SIMPLE_DATE_FORMAT = new SimpleDateFormat(DEFAULT_DATE_TIME);

    public static final DateTimeFormatter DEFAULT_FORMATTER_DATE_TIME = DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME);

    static {
        sdfMap.put(DEFAULT_DATE_TIME, DEFAULT_SIMPLE_DATE_FORMAT);
        dtfMap.put(DEFAULT_DATE_TIME, DEFAULT_FORMATTER_DATE_TIME);
    }

    /**
     * 默认的时区
     */
    private static final ZoneId DEFAULT_ZONE_ID = ZoneId.of("+8");
    private static final ZoneOffset DEFAULT_ZONE_OFFSET = ZoneOffset.of("+8");


    /**
     * 时间格式的 String 转换为 Date
     * 多线程下会出现异常
     */
    public static Date stringToDateSafe(String dateStr, String pattern) {
        LocalDateTime dateTime = stringToLocalDateTime(dateStr, pattern);
        return localDateTimeToDate(dateTime);
    }

    /**
     * 多线程下会出现异常
     */
    public static Date stringToDateSafe(String dateStr) {
        return stringToDateSafe(dateStr, DEFAULT_DATE_TIME);
    }

    /**
     * 时间格式的 String 转化为 LocalDateTime
     * 经过转换100W条数据测试这里做缓存和不做缓存的效率相差无几
     */
    public static LocalDateTime stringToLocalDateTime(String dateStr, String pattern) {
        DateTimeFormatter dateTimeFormatter = dtfMap.get(pattern);
        if (dateTimeFormatter == null) {
            dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
            dtfMap.put(pattern, dateTimeFormatter);
        }
        return LocalDateTime.parse(dateStr, dateTimeFormatter);
    }


    public static LocalDateTime stringToLocalDateTime(String dateStr) {
        return LocalDateTime.parse(dateStr, DEFAULT_FORMATTER_DATE_TIME);
    }

    /**
     * LocalDateTime 转化为 Date
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(DEFAULT_ZONE_ID).toInstant());
    }

    /**
     * LocalDateTime 转化为 String
     */
    public static String localDateTimeToString(LocalDateTime localDateTime, String pattern) {
        DateTimeFormatter dateTimeFormatter = dtfMap.get(pattern);
        if (dateTimeFormatter == null) {
            dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
            dtfMap.put(pattern, dateTimeFormatter);
        }
        return localDateTime.format(dateTimeFormatter);
    }

    public static String localDateTimeToString(LocalDateTime localDateTime) {
        return DEFAULT_FORMATTER_DATE_TIME.format(localDateTime);
    }

    /**
     * Date 转换为 LocalDateTime
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        return date.toInstant().atOffset(DEFAULT_ZONE_OFFSET).toLocalDateTime();
    }

    /**
     * Date 转换为 String
     */
    public static String dateToString(Date date, String pattern) {
        SimpleDateFormat sdf = sdfMap.get(pattern);
        if (sdf == null) {
            sdf = new SimpleDateFormat(pattern);
            sdfMap.put(pattern, sdf);
        }
        return sdf.format(date);
    }

    public static String dateToString(Date date) {
        return DEFAULT_SIMPLE_DATE_FORMAT.format(date);
    }


    /**
     * LocalDateTime 转化为 long
     */
    public static long getMillis(LocalDateTime localDateTime) {
        return localDateTime.toInstant(DEFAULT_ZONE_OFFSET).toEpochMilli();
    }

    /**
     * long 转化为 LocalDateTime
     */
    public static LocalDateTime longToLocalDateTime(long millis) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), DEFAULT_ZONE_ID);
    }


    /**
     * 计算两个时间戳之间相差多少  X年X月X日X时X分X秒
     *
     * @param bigTime
     * @param smallTime
     * @return
     */
    public static String getSubtractString(long bigTime, long smallTime) {
        long subtractTime = bigTime - smallTime;
        LocalDateTime subtractDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(subtractTime), DEFAULT_ZONE_ID).plusHours(-8);
        StringBuilder builder = new StringBuilder();
        int year = subtractDateTime.getYear() - 1970;
        if (year > 0) {
            builder.append(year).append("年");
        }
        int month = subtractDateTime.getMonthValue() - 1;
        if (month > 0) {
            builder.append(month).append("月");
        }
        int day = subtractDateTime.getDayOfMonth() - 1;
        if (day > 0) {
            builder.append(day).append("日");
        }
        int hour = subtractDateTime.getHour();
        if (hour > 0) {
            builder.append(hour).append("时");
        }
        int minute = subtractDateTime.getMinute();
        if (minute > 0) {
            builder.append(minute).append("分");
        }
        int second = subtractDateTime.getSecond();
        if (second > 0) {
            builder.append(second).append("秒");
        }
        return builder.toString();
    }

    /**
     * 计算两个日期间的年数
     *
     * @return
     */
    public static long calculateYears(LocalDate min, LocalDate max) {
        return ChronoUnit.YEARS.between(min, max);
    }

    /**
     * 计算两个日期间的月份数
     * 若不足一月就不进入计数
     */
    public static long calculateMonths(LocalDate min, LocalDate max) {
        return ChronoUnit.MONTHS.between(min, max);
    }

    /**
     * 计算两个日期之间天数
     */
    public static long calculateDays(LocalDate min, LocalDate max) {
        return ChronoUnit.DAYS.between(min, max);
    }


    /**
     * 计算两个日期之间的小时数
     */
    public static long calculateHours(LocalDateTime min, LocalDateTime max) {
        return ChronoUnit.HOURS.between(min, max);
    }


    /**
     * 计算两个日期之间的分钟数
     */
    public static long calculateMinutes(LocalDateTime min, LocalDateTime max) {
        return ChronoUnit.MINUTES.between(min, max);
    }

    /**
     * 计算两个日期之间的秒钟数
     */
    public static long calculateSeconds(LocalDateTime min, LocalDateTime max) {
        return ChronoUnit.SECONDS.between(min, max);
    }
}
